﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using LitJson;
using System.Threading;

class ServerManager
{
    private static ServerManager _instance;
    public static ServerManager Instance()
    {
        if (_instance == null)
        {
            _instance = new ServerManager();
        }
        return _instance;
    }

    Dictionary<string, SocketClient> dic = new Dictionary<string, SocketClient>();
    List<UserData> list = new List<UserData>();

    public static object lockObj = new object();

    TcpListener listener;
    string IP = "127.0.0.1";
    int Port = 8500;

    int HeartInterval = 5 * 1000;

    int PlayerCount = 15;
    int DeadCount = 0;

    private ServerManager()
    {
        IPAddress address = IPAddress.Parse(IP);
        listener = new TcpListener(address, Port);
        //绑定ip和port，进行侦听
        listener.Start();
        Console.WriteLine("开始侦听");

        //异步监听客户端连接
        listener.BeginAcceptTcpClient(OnAccecpt,null);

        Timer timer = new Timer(Callback,null, HeartInterval, HeartInterval);

        //System.Timers.Timer tim = new System.Timers.Timer();
        //tim.Interval = HeartInterval;
        //tim.Elapsed += Tim_Elapsed;
        //tim.Enabled = true;
    }
    //private void Tim_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    //{
    //    Console.WriteLine("一次心跳");
    //}

    void Callback(object state)
    {
        List<string> keys = new List<string>();
        foreach (var item in dic.Keys)
        {
            keys.Add(item);
        }
        for (int i = 0; i < keys.Count; i++)
        {
            SocketClient client = dic[keys[i]];
            client.SendMessage(Protocol.HeartBeat);
            client.timeOut++;
            if(client.timeOut>5)//4次心跳超时，服务器比客户端多判断一次
            {
                Console.WriteLine(client.userdata.username+ "心跳超时，断开链接");
                RemoveClient(client);
            }
        }
    }

    //客户端连接成功
    void OnAccecpt(IAsyncResult result)
    {
        //获取连接的客户端
        TcpClient client = listener.EndAcceptTcpClient(result);
        //封装到SocketClient里面，进行通信
        SocketClient remote = new SocketClient(client);

        //再次开启监听
        lock(listener)
        {
            listener.BeginAcceptTcpClient(OnAccecpt, null);
        }
    }

    public void BroadAll(int protocal)
    {
        lock (lockObj)
        {
            for (int i = 0; i < list.Count; i++)
            {
                string key = list[i].username;
                dic[key].SendMessage(protocal);
            }
        }
    }

    //广播所有人消息<包含自己>
    public void BroadAll(int protocal, string msg)
    {
        lock(lockObj)
        {
            for (int i = 0; i < list.Count; i++)
            {
                string key = list[i].username;
                dic[key].SendMessage(protocal, msg);
            }
        }
    }

    //广播给其他人
    public void BroadOther(SocketClient client,int protocal, string msg)
    {
        lock (lockObj)
        {
            for (int i = 0; i < list.Count; i++)
            {
                string key = list[i].username;
                if (key != client.userdata.username)
                {
                    dic[key].SendMessage(protocal, msg);
                }
            }
        }
    }

    //把断开的客户端，移除掉
    public void RemoveClient(SocketClient client)
    {
        lock (lockObj)
        {
            //连接socket但未登陆的用户不用移除
            if (client.userdata != null)
            {
                string username = client.userdata.username;

                Console.WriteLine(username + "：断开链接");
                dic.Remove(client.userdata.username);
                list.Remove(client.userdata);

                //广播给所有人，玩家退出游戏
                BroadAll(Protocol.PlayerLogOut, JsonMapper.ToJson(client.userdata));
            }
        }
    }
        
    //接收客户端消息，并进行分发
    public void OnMessage(SocketClient client,int protocol,string msg)
    {
        switch (protocol)
        {
            case Protocol.Login_CMD:
                //玩家超过限定人数，防止继续进入
                if (list.Count >= PlayerCount)
                {
                    return;
                }
                bool hasplayer = false;
                UserData user = JsonMapper.ToObject<UserData>(msg);

                //已经存在玩家
                if (dic.ContainsKey(user.username))
                {
                    //还没有往字典存，client就是当前登录的玩家
                    client.SendMessage(Protocol.PlayerRepeatExit);
                }
                else//把新连接用户存储起来
                {
                    //登录后，才保存用户的信息
                    client.userdata = JsonMapper.ToObject<UserData>(msg);
                    dic.Add(client.userdata.username, client);
                    list.Add(client.userdata);//存储到list中
                    //赋值index
                    client.userdata.index = list.IndexOf(client.userdata);

                    //广播新用户登录
                    string userJson = JsonMapper.ToJson(client.userdata);
                    BroadOther(client, protocol, userJson);

                    //通知新用户登录成功
                    dic[client.userdata.username].SendMessage(Protocol.SelfLogin_CMD, userJson);
                    //通知新用户，其他玩家数据
                    dic[client.userdata.username].SendMessage(Protocol.OtherPlayerInfo_CMD, JsonMapper.ToJson(list));
                }
                break;
            case Protocol.PlayerPosition_CMD:
                BroadOther(client, protocol, msg);
                break;
            case Protocol.PlayerMove_CMD:
                BroadOther(client, protocol, msg);
                break;
            case Protocol.PlayerFire_CMD:
                BroadOther(client, protocol, msg);
                break;
            case Protocol.PlayerOnHit_CMD:
                HitDat data = JsonMapper.ToObject<HitDat>(msg);

                string username = data.targetUsername;
                foreach (var item in dic)
                {
                    if (item.Value.userdata.username == username)
                    {
                        data.hp = --item.Value.userdata.hp;
                        BroadAll(protocol, JsonMapper.ToJson(data));
                        //玩家已经死亡
                        if (data.hp <= 0)
                        {
                            DeadCount++;
                            BroadAll(Protocol.PlayerDead_CMD, JsonMapper.ToJson(item.Value.userdata));

                            //剩余最后一名玩家
                            if (DeadCount >= PlayerCount - 1)
                            {
                                for (int i = 0; i < list.Count; i++)
                                {
                                    if (list[i].hp > 0)
                                    {
                                        BroadAll(Protocol.PlayerWin_CMD, JsonMapper.ToJson(list[i]));
                                        break;
                                    }
                                }
                            }
                        }
                        break;
                    }
                }
                break;
            case Protocol.HeartBeat:
                client.timeOut = 0;
                break;
            case Protocol.PlayerReady_CMD://找到该玩家，广播他的所有信息
                client.userdata.isReady = true;
                string json = JsonMapper.ToJson(client.userdata);
                BroadAll(protocol, json);

                //全部准备，开始游戏
                int readyCount = 0;
                foreach (var item in list)
                {
                    if (item.isReady)
                    {
                        readyCount++;
                    }
                }
                if (readyCount >= PlayerCount)
                {
                    DeadCount = 0;
                    BroadAll(Protocol.ReadyGoToGame_CMD, JsonMapper.ToJson(list));
                }
                break;

            case Protocol.UserRegister_CMD://注册
                User user001 = JsonMapper.ToObject<User>(msg);

                User old = MysqlManager.Instance.SelectByUserName<User>(user001.username);

                if (old != null)
                {
                    Error error = new Error(101);
                    client.SendMessage(Protocol.Errer_CMD, JsonMapper.ToJson(error));
                }
                else
                {
                    int count = MysqlManager.Instance.InsertInto(user001);
                    if (count > 0)
                    {
                        client.SendMessage(Protocol.UserRegister_CMD, msg);
                    }
                    else
                    {
                        Error error = new Error(110);
                        client.SendMessage(Protocol.Errer_CMD, JsonMapper.ToJson(error));
                    }
                }
                break;
            case Protocol.UserLogin_CMD://登录
                User user002 = JsonMapper.ToObject<User>(msg);

                User user003 = MysqlManager.Instance.SelectByUserName<User>(user002.username);
                if(user003!=null)
                {
                    client.SendMessage(Protocol.UserLogin_CMD, msg);
                }
                break;
            default:
                break;
        }
    }
}
